import or1200_definitions
import sys
sys.path.append("..")
import pyrtl
from pyrtl.corecircuits import mux
from  pyrtl import GPUSim
from or1200_genpc import Or1200Genpc_wire
from or1200_if import Or1200If_wire
from or1200_ctrl import Or1200Ctrl_wire
from or1200_rf import Or1200Rf_wire
from or1200_operandmuxes import Or1200Operandmuxes_wire
from or1200_alu import Or1200Alu_wire
from or1200_sprs import Or1200sprs_wire
from or1200_lsu import Or1200Lsu_wire
from or1200_wbmux import Or1200wbmux_wire
from or1200_freeze import Or1200Freeze_wire
from or1200_except import Or1200Except_wire, FlagPipelines1, DelayedIee, DelayedTee, FlagPipelines2, FlagPipelines3, \
    ExceptionFSM
from or1200_cfgr import Or1200Cfgr_wire
import time

dw = or1200_definitions.OR1200_OPERAND_WIDTH
aw = or1200_definitions.OR1200_REGFILE_ADDR_WIDTH
OR1200_EXCEPTFSM_WIDTH = 3
OR1200_EXCEPTFSM_IDLE = pyrtl.Const(0, bitwidth=OR1200_EXCEPTFSM_WIDTH)
OR1200_EXCEPTFSM_FLU1 = pyrtl.Const(1, bitwidth=OR1200_EXCEPTFSM_WIDTH)
OR1200_EXCEPTFSM_FLU2 = pyrtl.Const(2, bitwidth=OR1200_EXCEPTFSM_WIDTH)
OR1200_EXCEPTFSM_FLU3 = pyrtl.Const(3, bitwidth=OR1200_EXCEPTFSM_WIDTH)
OR1200_EXCEPTFSM_FLU4 = pyrtl.Const(4, bitwidth=OR1200_EXCEPTFSM_WIDTH)
OR1200_EXCEPTFSM_FLU5 = pyrtl.Const(5, bitwidth=OR1200_EXCEPTFSM_WIDTH)


class Or1200Cpu(object):
    def __init__(self):
        # Clk & Rst
        # self.clk = pyrtl.Input(bitwidth=1, name='clk')
        self.rst = pyrtl.Input(bitwidth=1, name='cpu_rst')

        # Insn (IC) interface
        #self.ic_en = pyrtl.Output(bitwidth=1, name='ic_en')
        self.ic_en = pyrtl.WireVector(bitwidth=1, name='ic_en')
        self.icpu_adr_o = pyrtl.WireVector(bitwidth=32, name='icpu_adr_o')
        #self.icpu_adr_o = pyrtl.Output(bitwidth=3, name='icpu_adr_o')
        self.icpu_cycstb_o = pyrtl.WireVector(bitwidth=1, name='icpu_cycstb_o')
        #self.icpu_cycstb_o = pyrtl.Output(bitwidth=1, name='icpu_cycstb_o')
        self.icpu_sel_o = pyrtl.WireVector(bitwidth=4, name='icpu_sel_o')
        self.icpu_tag_o = pyrtl.WireVector(bitwidth=4, name='icpu_tag_o')
        #self.icpu_sel_o = pyrtl.Output(bitwidth=4, name='icpu_sel_o')
        #self.icpu_tag_o = pyrtl.Output(bitwidth=4, name='icpu_tag_o')
        self.icpu_dat_i = pyrtl.Input(bitwidth=32, name='cpu_icpu_dat_i')
        self.icpu_ack_i = pyrtl.Input(bitwidth=1, name='cpu_icpu_ack_i')
        self.icpu_rty_i = pyrtl.Input(bitwidth=1, name='cpu_icpu_rty_i')
        self.icpu_err_i = pyrtl.Input(bitwidth=1, name='cpu_icpu_err_i')
        self.icpu_tag_i = pyrtl.Input(bitwidth=4, name='cpu_icpu_tag_i')

        # Debug interface
        #self.ex_insn = pyrtl.Output(bitwidth=32, name='ex_insn') ####
        self.ex_insn = pyrtl.WireVector(bitwidth=32, name='ex_insn') ####
        self.ex_freeze = pyrtl.Register(bitwidth=1, name='ex_freeze')
        #self.id_pc = pyrtl.Output(bitwidth=32, name='id_pc') ####
        self.id_pc = pyrtl.WireVector(bitwidth=32, name='id_pc') ####
        self.branch_op = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_BRANCHOP_WIDTH, name='branch_op')
        # self.test_branch_op = pyrtl.Output(bitwidth=or1200_definitions.OR1200_BRANCHOP_WIDTH, name='test_branch_op')
        # self.test_branch_op<<=self.branch_op

        self.du_stall = pyrtl.Input(bitwidth=1, name='cpu_du_stall')
        self.du_addr = pyrtl.Input(bitwidth=dw, name='cpu_du_addr')
        self.du_dat_du = pyrtl.Input(bitwidth=dw, name='cpu_du_dat_du')
        self.du_read = pyrtl.Input(bitwidth=1, name='cpu_du_read')
        self.du_write = pyrtl.Input(bitwidth=1, name='cpu_du_write')
        self.du_dsr = pyrtl.Input(bitwidth=or1200_definitions.OR1200_DU_DSR_WIDTH, name='cpu_du_dsr')
        self.du_hwbkpt = pyrtl.Input(bitwidth=1, name='cpu_du_hwbkpt')
        self.rf_dataw = pyrtl.WireVector(bitwidth=dw, name='rf_dataw')
        #self.du_except = pyrtl.Output(bitwidth=13, name='du_except')  ###
        self.du_except = pyrtl.WireVector(bitwidth=13, name='du_except')  ###
        self.du_dat_cpu = pyrtl.Output(bitwidth=dw, name='du_dat_cpu')

        # Data (DC) interface
        self.dcpu_adr_o = pyrtl.WireVector(bitwidth=32, name='dcpu_adr_o')
        self.dcpu_dat_i = pyrtl.Input(bitwidth=32, name='cpu_dcpu_dat_i') #, name='dcpu_dat_i')
        self.dcpu_ack_i = pyrtl.Input(bitwidth=1, name='cpu_dcpu_ack_i') #, name='dcpu_ack_i')
        self.dcpu_rty_i = pyrtl.Input(bitwidth=1, name='cpu_dcpu_rty_i') #, name='dcpu_rty_i')
        self.dcpu_err_i = pyrtl.Input(bitwidth=1, name='cpu_dcpu_err_i') #, name='dcpu_err_i')
        self.dcpu_tag_i = pyrtl.Input(bitwidth=4, name='cpu_dcpu_tag_i') #, name='dcpu_tag_i')
        # self.dc_en = pyrtl.Output(bitwidth=1, name='dc_en')
        # self.dcpu_cycstb_o = pyrtl.Output(bitwidth=1, name='dcpu_cycstb_o')
        # self.dcpu_we_o = pyrtl.Output(bitwidth=1, name='dcpu_we_o')
        # self.dcpu_sel_o = pyrtl.Output(bitwidth=4, name='dcpu_sel_o')
        # self.dcpu_tag_o = pyrtl.Output(bitwidth=4, name='dcpu_tag_o')
        self.dc_en = pyrtl.WireVector(bitwidth=1, name='dc_en')
        self.dcpu_cycstb_o = pyrtl.WireVector(bitwidth=1, name='dcpu_cycstb_o')
        self.dcpu_we_o = pyrtl.WireVector(bitwidth=1, name='dcpu_we_o')
        self.dcpu_sel_o = pyrtl.WireVector(bitwidth=4, name='dcpu_sel_o')
        self.dcpu_tag_o = pyrtl.WireVector(bitwidth=4, name='dcpu_tag_o')
        self.dcpu_dat_o = pyrtl.Output(bitwidth=32, name='dcpu_dat_o')



        # SPR interface
        self.supv = pyrtl.Output(bitwidth=1, name='supv')
        self.spr_dat_pic = pyrtl.Input(bitwidth=dw, name='cpu_spr_dat_pic') #, name='spr_dat_pic')
        self.spr_dat_tt = pyrtl.Input(bitwidth=dw, name='cpu_spr_dat_tt') #, name='spr_dat_tt')
        self.spr_dat_pm = pyrtl.Input(bitwidth=dw, name='cpu_spr_dat_pm') #, name='spr_dat_pm')
        self.spr_dat_du = pyrtl.Input(bitwidth=dw, name='cpu_spr_dat_du') #, name='spr_dat_du')
        self.spr_addr = pyrtl.WireVector(bitwidth=dw, name='spr_addr')
        self.spr_dat_cpu = pyrtl.WireVector(bitwidth=dw, name='spr_dat_cpu')
        self.spr_dat_npc = pyrtl.WireVector(bitwidth=dw, name='spr_dat_npc')
        self.spr_cs = pyrtl.WireVector(bitwidth=32, name='spr_cs')
        self.spr_we = pyrtl.WireVector(bitwidth=1, name='spr_we')

        # Interrupt exceptions
        self.sig_int = pyrtl.Input(bitwidth=1, name='cpu_sig_int') #, name='sig_int')
        self.sig_tick = pyrtl.Input(bitwidth=1, name='cpu_sig_tick') #, name='sig_tick')

        # Internal wires
        self.if_insn = pyrtl.Register(bitwidth=32) #, name='if_insn')
        self.if_pc = pyrtl.WireVector(bitwidth=32) #, name='if_pc')
        self.lr_sav = pyrtl.WireVector(bitwidth=30) #, name='lr_sav')
        self.rf_addrw = pyrtl.WireVector(bitwidth=aw) #, name='rf_addrw')
        self.rf_addra = pyrtl.WireVector(bitwidth=aw) #, name='rf_addra')
        self.rf_addrb = pyrtl.WireVector(bitwidth=aw) #, name='rf_addrb')
        self.rf_rda = pyrtl.WireVector(bitwidth=1) #, name='rf_rda')
        self.rf_rdb = pyrtl.WireVector(bitwidth=1) #, name='rf_rdb')
        self.simm = pyrtl.WireVector(bitwidth=dw) #, name='simm')
        self.branch_addrofs = pyrtl.WireVector(bitwidth=dw - 2) #, name='branch_addrofs')
        self.alu_op = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_ALUOP_WIDTH) #, name='alu_op')
        self.shrot_op = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_SHROTOP_WIDTH) #, name='shrot_op')
        self.comp_op = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_COMPOP_WIDTH) #, name='comp_op')
        # self.branch_op = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_BRANCHOP_WIDTH, name='branch_op')
        self.lsu_op = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_LSUOP_WIDTH) #, name='lsu_op')
        self.genpc_freeze = pyrtl.WireVector(bitwidth=1) #, name='genpc_freeze')
        self.if_freeze = pyrtl.WireVector(bitwidth=1) #, name='if_freeze')
        self.id_freeze = pyrtl.Register(bitwidth=1) #, name='id_freeze')
        # self.ex_freeze = pyrtl.WireVector(bitwidth=1, name='ex_freeze')
        self.wb_freeze = pyrtl.WireVector(bitwidth=1) #, name='wb_freeze')
        self.sel_a = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_SEL_WIDTH) #, name='sel_a')
        self.sel_b = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_SEL_WIDTH) #, name='sel_b')
        self.rfwb_op = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_RFWBOP_WIDTH) #, name='rfwb_op')
        # self.rf_dataw = pyrtl.WireVector(bitwidth=dw, name='rf_dataw')
        self.rf_dataa = pyrtl.WireVector(bitwidth=dw) #, name='rf_dataa')
        self.rf_datab = pyrtl.WireVector(bitwidth=dw) #, name='rf_datab')

        self.wb_forw = pyrtl.WireVector(bitwidth=dw) #, name='wb_forw')
        self.wbforw_valid = pyrtl.WireVector(bitwidth=1) #, name='wbforw_valid')
        self.operand_a = pyrtl.WireVector(bitwidth=dw) #, name='operand_a')
        self.operand_b = pyrtl.WireVector(bitwidth=dw) #, name='operand_b')
        self.alu_dataout = pyrtl.WireVector(bitwidth=dw) #, name='alu_dataout')
        self.lsu_dataout = pyrtl.WireVector(bitwidth=dw) #, name='lsu_dataout')
        self.sprs_dataout = pyrtl.WireVector(bitwidth=dw) #, name='sprs_dataout')
        self.lsu_addrofs = pyrtl.WireVector(bitwidth=32) #, name='lsu_addrofs')
        self.multicycle = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_MULTICYCLE_WIDTH) #, name='multicycle')
        self.except_type = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_EXCEPT_WIDTH) #, name='except_type')
        self.flushpipe = pyrtl.Register(bitwidth=1) #, name='flushpipe')
        self.extend_flush = pyrtl.WireVector(bitwidth=1) #, name='extend_flush')
        self.branch_taken = pyrtl.WireVector(bitwidth=1) #, name='branch_taken')
        self.flag = pyrtl.WireVector(bitwidth=1) #, name='flag')
        self.flagforw = pyrtl.WireVector(bitwidth=1) #, name='flagforw')
        self.flag_we = pyrtl.WireVector(bitwidth=1) #, name='flag_we')
        self.carry = pyrtl.WireVector(bitwidth=1) #, name='carry')
        self.cyforw = pyrtl.WireVector(bitwidth=1) #, name='cyforw')
        self.cy_we = pyrtl.WireVector(bitwidth=1) #, name='cy_we')
        self.lsu_stall = pyrtl.WireVector(bitwidth=1) #, name='lsu_stall')
        self.epcr_we = pyrtl.WireVector(bitwidth=1) #, name='epcr_we')
        self.eear_we = pyrtl.WireVector(bitwidth=1) #, name='eear_we')
        self.esr_we = pyrtl.WireVector(bitwidth=1) #, name='esr_we')
        self.pc_we = pyrtl.WireVector(bitwidth=1) #, name='pc_we')
        self.epcr = pyrtl.WireVector(bitwidth=32) #, name='epcr')
        self.eear = pyrtl.WireVector(bitwidth=32) #, name='eear')
        self.esr = pyrtl.Register(bitwidth=or1200_definitions.OR1200_SR_WIDTH, name='cpu_esr')
        self.sr_we = pyrtl.WireVector(bitwidth=1) #, name='sr_we')
        #self.to_sr = pyrtl.Register(bitwidth=or1200_definitions.OR1200_SR_WIDTH) #, name='to_sr')
        #self.sr = pyrtl.Register(bitwidth=or1200_definitions.OR1200_SR_WIDTH) #, name='sr')
        self.to_sr = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_SR_WIDTH)  # , name='to_sr')
        self.sr = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_SR_WIDTH)  # , name='sr')

        self.except_start = pyrtl.WireVector(bitwidth=1) #, name='except_start')
        self.except_started = pyrtl.WireVector(bitwidth=1) #, name='except_started')
        # self.test_sr = pyrtl.Output(bitwidth=or1200_definitions.OR1200_SR_WIDTH, name='test_to_sr')
        # self.test_sr <<= self.sr
        # self.test_operand_a = pyrtl.Output(bitwidth=dw, name='test_operand_a')
        # self.test_operand_b = pyrtl.Output(bitwidth=dw, name='test_operand_b')
        # self.test_operand_a<<=self.operand_a
        # self.test_operand_b<<=self.operand_b
        # # self.test_lsu_addrofs = pyrtl.Output(bitwidth=32, name='test_lsu_addrofs')
        # # self.test_lsu_addrofs<<=self.lsu_addrofs
        # # self.test_lsu_op = pyrtl.Output(bitwidth=or1200_definitions.OR1200_LSUOP_WIDTH, name='test_lsu_op')
        # # self.test_lsu_op<<=self.lsu_op
        # self.test_ex_freeze = pyrtl.Output(bitwidth=1, name='if_freeze')
        # self.test_id_freeze = pyrtl.Output(bitwidth=1, name='id_freeze')
        # self.test_rf_dataa = pyrtl.Output(bitwidth=dw, name='rf_dataa')
        # self.test_rf_datab = pyrtl.Output(bitwidth=dw, name='rf_datab')
        #
        # self.test_ex_freeze <<= self.ex_freeze
        # self.test_id_freeze <<= self.id_freeze


        self.wb_insn = pyrtl.WireVector(bitwidth=32) #, name='wb_insn')
        self.spr_addrimm = pyrtl.WireVector(bitwidth=16) #, name='spr_addrimm')
        self.sig_syscall = pyrtl.WireVector(bitwidth=1) #, name='sig_syscall')
        self.sig_trap = pyrtl.WireVector(bitwidth=1) #, name='sig_trap')
        self.spr_dat_cfgr = pyrtl.WireVector(bitwidth=32) #, name='spr_dat_cfgr')
        self.spr_dat_rf = pyrtl.WireVector(bitwidth=32) #, name='spr_dat_rf')
        # self.spr_dat_npc = pyrtl.WireVector(bitwidth=32) #, name='spr_dat_npc')
        self.spr_dat_ppc = pyrtl.WireVector(bitwidth=32) #, name='spr_dat_ppc')
        self.force_dslot_fetch = pyrtl.WireVector(bitwidth=1) #, name='force_dslot_fetch')
        self.no_more_dslot = pyrtl.WireVector(bitwidth=1) #, name='no_more_dslot')
        self.ex_void = pyrtl.WireVector(bitwidth=1) #, name='ex_void')
        self.if_stall = pyrtl.WireVector(bitwidth=1) #, name='if_stall')
        self.except_stop = pyrtl.WireVector(bitwidth=13) #, name='except_stop')
        self.genpc_refetch = pyrtl.WireVector(bitwidth=1) #, name='genpc_refetch')
        self.rfe = pyrtl.WireVector(bitwidth=1) #, name='rfe')
        self.lsu_unstall = pyrtl.WireVector(bitwidth=1) #, name='lsu_unstall')
        self.except_align = pyrtl.WireVector(bitwidth=1) #, name='except_align')
        self.except_illegal = pyrtl.WireVector(bitwidth=1) #, name='except_illegal')
        self.except_ibuserr = pyrtl.WireVector(bitwidth=1) #, name='except_ibuserr')
        self.except_dbuserr = pyrtl.WireVector(bitwidth=1) #, name='except_dbuserr')
        self.abort_ex = pyrtl.WireVector(bitwidth=1) #, name='abort_ex')
        self.icpu_adr_o_r = pyrtl.WireVector(bitwidth=1) #, name='icpu_adr_o_r')

        # Send exceptions to Debug Unit
        self.du_except <<= self.except_stop
        # Data cache enable
        self.dc_en <<= self.sr[or1200_definitions.OR1200_SR_DCE]
        # Instruction cache enable
        self.ic_en <<= self.sr[or1200_definitions.OR1200_SR_ICE]
        # SUPV bit
        self.supv <<= self.sr[or1200_definitions.OR1200_SR_SM]

        # Instantiation of instruction fetch block 444
        or1200genpc = Or1200Genpc_wire()
        or1200genpc.rst <<= self.rst
        self.icpu_adr_o <<= or1200genpc.icpu_adr_o_out
        self.icpu_adr_o_r <<= or1200genpc.icpu_adr_o_r_out
        self.icpu_cycstb_o <<= or1200genpc.icpu_cycstb_o
        self.icpu_sel_o <<= or1200genpc.icpu_sel_o
        self.icpu_tag_o <<= or1200genpc.icpu_tag_o
        or1200genpc.icpu_rty_i <<= self.icpu_rty_i
        or1200genpc.branch_op <<= self.branch_op
        or1200genpc.except_type <<= self.except_type
        or1200genpc.except_start <<= self.except_start
        or1200genpc.except_prefix <<= self.sr[or1200_definitions.OR1200_SR_EPH]
        or1200genpc.branch_addrofs <<= self.branch_addrofs
        or1200genpc.lr_restor <<= self.operand_b
        or1200genpc.flag <<= self.flag
        self.branch_taken <<= or1200genpc.taken
        or1200genpc.binsn_addr <<= self.lr_sav
        or1200genpc.epcr <<= self.epcr
        or1200genpc.spr_dat_i <<= self.spr_dat_cpu
        or1200genpc.spr_pc_we <<= self.pc_we
        or1200genpc.genpc_refetch <<= self.genpc_refetch
        or1200genpc.genpc_freeze <<= self.genpc_freeze
        or1200genpc.genpc_stop_prefetch <<= pyrtl.Const(0b0, bitwidth=1)
        or1200genpc.no_more_dslot <<= self.no_more_dslot

        # Instantiation of instruction fetch block 5555
        or1200if = Or1200If_wire()
        or1200if.rst <<= self.rst
        or1200if.icpu_dat_i <<= self.icpu_dat_i
        or1200if.icpu_ack_i <<= self.icpu_ack_i
        or1200if.icpu_err_i <<= self.icpu_err_i
        or1200if.icpu_adr_i <<= self.icpu_adr_o_r
        or1200if.icpu_tag_i <<= self.icpu_tag_i
        or1200if.if_freeze <<= self.if_freeze
        self.if_insn.next <<= or1200if.if_insn
        self.if_pc <<= or1200if.if_pc
        or1200if.flushpipe <<= self.flushpipe
        self.if_stall <<= or1200if.if_stall
        or1200if.no_more_dslot <<= self.no_more_dslot
        self.genpc_refetch <<= or1200if.genpc_refetch
        or1200if.rfe <<= self.rfe
        self.except_ibuserr <<= or1200if.except_ibuserr

        # Instantiation of instruction decode/control logic 555
        or1200ctrl = Or1200Ctrl_wire()
        or1200ctrl.rst <<= self.rst
        or1200ctrl.id_freeze <<= self.id_freeze
        or1200ctrl.ex_freeze <<= self.ex_freeze
        or1200ctrl.wb_freeze <<= self.wb_freeze
        or1200ctrl.flushpipe <<= self.flushpipe
        or1200ctrl.if_insn <<= self.if_insn
        self.ex_insn <<= or1200ctrl.ex_insn_out
        self.branch_op <<= or1200ctrl.branch_op_out
        or1200ctrl.branch_taken <<= self.branch_taken
        self.rf_addra <<= or1200ctrl.rf_addra
        self.rf_addrb <<= or1200ctrl.rf_addrb
        self.rf_rda <<= or1200ctrl.rf_rda
        self.rf_rdb <<= or1200ctrl.rf_rdb
        self.alu_op <<= or1200ctrl.alu_op
        self.shrot_op <<= or1200ctrl.shrot_op
        self.comp_op <<= or1200ctrl.comp_op
        self.rf_addrw <<= or1200ctrl.rf_addrw_out
        self.rfwb_op <<= or1200ctrl.rfwb_op_out
        self.wb_insn <<= or1200ctrl.wb_insn
        self.simm <<= or1200ctrl.simm
        self.branch_addrofs <<= or1200ctrl.branch_addrofs
        self.lsu_addrofs <<= or1200ctrl.lsu_addrofs
        self.sel_a <<= or1200ctrl.sel_a
        self.sel_b <<= or1200ctrl.sel_b
        self.lsu_op <<= or1200ctrl.lsu_op_out
        self.multicycle <<= or1200ctrl.multicycle
        self.spr_addrimm <<= or1200ctrl.spr_addrimm
        or1200ctrl.wbforw_valid <<= self.wbforw_valid
        self.sig_syscall <<= or1200ctrl.sig_syscall
        self.sig_trap <<= or1200ctrl.sig_trap
        self.force_dslot_fetch <<= or1200ctrl.force_dslot_fetch
        self.no_more_dslot <<= or1200ctrl.no_more_dslot
        self.ex_void <<= or1200ctrl.ex_void
        self.rfe <<= or1200ctrl.rfe
        or1200ctrl.du_hwbkpt <<= self.du_hwbkpt
        self.except_illegal <<= or1200ctrl.except_illegal

        # Instantiation of register file
        or1200rf = Or1200Rf_wire()
        or1200rf.rst <<= self.rst
        or1200rf.supv <<= self.sr[or1200_definitions.OR1200_SR_SM]
        or1200rf.wb_freeze <<= self.wb_freeze
        or1200rf.addrw <<= self.rf_addrw
        or1200rf.dataw <<= self.rf_dataw
        or1200rf.id_freeze <<= self.id_freeze
        or1200rf.we <<= self.rfwb_op[0]
        or1200rf.flushpipe <<= self.flushpipe
        or1200rf.addra <<= self.rf_addra
        or1200rf.rda <<= self.rf_rda
        self.rf_dataa <<= or1200rf.dataa
        or1200rf.addrb <<= self.rf_addrb
        or1200rf.rdb <<= self.rf_rdb
        self.rf_datab <<= or1200rf.datab
        or1200rf.spr_cs <<= self.spr_cs[or1200_definitions.OR1200_SPR_GROUP_SYS.val]
        or1200rf.spr_write <<= self.spr_we
        or1200rf.spr_addr <<= self.spr_addr
        or1200rf.spr_dat_i <<= self.spr_dat_cpu
        self.spr_dat_rf <<= or1200rf.spr_dat_o

        # Instantiation of operand muxes 555
        or1200openandmuxes = Or1200Operandmuxes_wire()
        or1200openandmuxes.rst <<= self.rst
        or1200openandmuxes.id_freeze <<= self.id_freeze
        or1200openandmuxes.ex_freeze <<= self.ex_freeze
        or1200openandmuxes.rf_dataa <<= self.rf_dataa
        or1200openandmuxes.rf_datab <<= self.rf_datab
        or1200openandmuxes.ex_forw <<= self.rf_dataw
        or1200openandmuxes.wb_forw <<= self.wb_forw
        or1200openandmuxes.simm <<= self.simm
        or1200openandmuxes.sel_a <<= self.sel_a
        or1200openandmuxes.sel_b <<= self.sel_b
        self.operand_a <<= or1200openandmuxes.operand_a
        self.operand_b <<= or1200openandmuxes.operand_b


        # Instantiation of CPU's ALU 444
        or1200alu = Or1200Alu_wire()
        or1200alu.a <<= self.operand_a
        or1200alu.b <<= self.operand_b
        or1200alu.alu_op <<= self.alu_op
        or1200alu.shrot_op <<= self.shrot_op
        or1200alu.comp_op <<= self.comp_op
        self.alu_dataout <<= or1200alu.result
        self.flagforw <<= or1200alu.flagforw
        self.flag_we <<= or1200alu.flag_we
        self.cyforw <<= or1200alu.cyforw
        self.cy_we <<= or1200alu.cy_we
        or1200alu.flag <<= self.flag
        or1200alu.carry <<= self.carry



        # Instantiation of load/store unit 555
        or1200lsu = Or1200Lsu_wire()
        or1200lsu.addrbase <<= self.operand_a
        or1200lsu.addrofs <<= self.lsu_addrofs
        or1200lsu.lsu_op <<= self.lsu_op
        or1200lsu.lsu_datain <<= self.operand_b
        self.lsu_dataout <<= or1200lsu.lsu_dataout
        self.lsu_stall <<= or1200lsu.lsu_stall
        self.lsu_unstall <<= or1200lsu.lsu_unstall_out
        or1200lsu.du_stall <<= self.du_stall
        self.except_align <<= or1200lsu.except_align_out
        self.except_dbuserr <<= or1200lsu.except_dbuserr
        self.dcpu_adr_o <<= or1200lsu.dcpu_adr_o_out
        self.dcpu_cycstb_o <<= or1200lsu.dcpu_cycstb_o_out
        self.dcpu_we_o <<= or1200lsu.dcpu_we_o
        self.dcpu_sel_o <<= or1200lsu.dcpu_sel_o
        self.dcpu_tag_o <<= or1200lsu.dcpu_tag_o
        self.dcpu_dat_o <<= or1200lsu.dcpu_dat_o
        or1200lsu.dcpu_dat_i <<= self.dcpu_dat_i
        or1200lsu.dcpu_ack_i <<= self.dcpu_ack_i
        or1200lsu.dcpu_rty_i <<= self.dcpu_rty_i
        or1200lsu.dcpu_err_i <<= self.dcpu_err_i
        or1200lsu.dcpu_tag_i <<= self.dcpu_tag_i

        # Instantiation of write-back muxes 5555
        or1200wbmux = Or1200wbmux_wire()
        or1200wbmux.rst <<= self.rst
        or1200wbmux.wb_freeze <<= self.wb_freeze
        or1200wbmux.rfwb_op <<= self.rfwb_op
        or1200wbmux.muxin_a <<= self.alu_dataout
        or1200wbmux.muxin_b <<= self.lsu_dataout
        or1200wbmux.muxin_c <<= self.sprs_dataout
        or1200wbmux.muxin_d <<= pyrtl.concat(self.sprs_dataout, pyrtl.Const(0b0, bitwidth=2))
        self.rf_dataw <<= or1200wbmux.muxout_out
        self.wb_forw <<= or1200wbmux.muxreg
        self.wbforw_valid <<= or1200wbmux.muxreg_valid

        # Instantiation of freeze logic 55555
        or1200freeze = Or1200Freeze_wire()
        or1200freeze.rst <<= self.rst
        or1200freeze.multicycle <<= self.multicycle
        or1200freeze.flushpipe <<= self.flushpipe
        or1200freeze.extend_flush <<= self.extend_flush
        or1200freeze.lsu_stall <<= self.lsu_stall
        or1200freeze.if_stall <<= self.if_stall
        or1200freeze.lsu_unstall <<= self.lsu_unstall
        or1200freeze.force_dslot_fetch <<= self.force_dslot_fetch
        or1200freeze.abort_ex <<= self.abort_ex
        or1200freeze.du_stall <<= self.du_stall
        self.genpc_freeze <<= or1200freeze.genpc_freeze_out
        self.if_freeze <<= or1200freeze.if_freeze
        self.id_freeze.next <<= or1200freeze.id_freeze_out
        self.ex_freeze.next <<= or1200freeze.ex_freeze
        self.wb_freeze <<= or1200freeze.wb_freeze_out
        or1200freeze.icpu_ack_i <<= self.icpu_ack_i
        or1200freeze.icpu_err_i <<= self.icpu_err_i

        # Instantiation of exception block
        # Instantiation of exception block  55555
        or1200except = Or1200Except_wire()
        or1200except.rst <<= self.rst
        or1200except.sig_ibuserr <<= self.except_ibuserr
        or1200except.sig_dbuserr <<= self.except_dbuserr
        or1200except.sig_illegal <<= self.except_illegal
        or1200except.sig_align <<= self.except_align
        or1200except.sig_range <<= pyrtl.Const(0b0, bitwidth=1)
        or1200except.sig_int <<= self.sig_int
        or1200except.sig_syscall <<= self.sig_syscall
        or1200except.sig_trap <<= self.sig_trap
        or1200except.sig_tick <<= self.sig_tick
        or1200except.branch_taken <<= self.branch_taken
        or1200except.icpu_ack_i <<= self.icpu_ack_i
        or1200except.icpu_err_i <<= self.icpu_err_i
        or1200except.dcpu_ack_i <<= self.dcpu_ack_i
        or1200except.dcpu_err_i <<= self.dcpu_err_i
        or1200except.genpc_freeze <<= self.genpc_freeze
        or1200except.id_freeze <<= self.id_freeze
        or1200except.ex_freeze <<= self.ex_freeze
        or1200except.wb_freeze <<= self.wb_freeze
        or1200except.if_stall <<= self.if_stall
        or1200except.if_pc <<= self.if_pc
        or1200except.except_trig_pending_tick <<= self.sig_tick
        or1200except.except_trig_pending_int <<= self.sig_int
        self.id_pc <<= or1200except.id_pc_out
        self.lr_sav <<= or1200except.lr_sav
        self.flushpipe.next <<= or1200except.flushpipe_out
        self.extend_flush <<= or1200except.extend_flush_out
        self.except_type <<= or1200except.except_type_out
        self.except_start <<= or1200except.except_start_out
        self.except_started <<= or1200except.except_started
        self.except_stop <<= or1200except.except_stop
        or1200except.ex_void <<= self.ex_void
        self.spr_dat_ppc <<= or1200except.spr_dat_ppc
        self.spr_dat_npc <<= or1200except.spr_dat_npc
        or1200except.datain <<= self.operand_b
        or1200except.du_dsr <<= self.du_dsr
        or1200except.epcr_we <<= self.epcr_we
        or1200except.eear_we <<= self.eear_we
        or1200except.esr_we <<= self.esr_we
        or1200except.pc_we <<= self.pc_we
        self.epcr <<= or1200except.epcr
        self.eear <<= or1200except.eear
        self.esr.next <<= or1200except.esr
        or1200except.lsu_addr <<= self.dcpu_adr_o
        or1200except.sr_we <<= self.sr_we
        or1200except.to_sr <<= self.to_sr
        or1200except.sr <<= self.sr
        self.abort_ex <<= or1200except.abort_ex

        # Instantiation of configuration registers %%%
        or1200cfgr = Or1200Cfgr_wire()
        or1200cfgr.spr_addr <<= self.spr_addr
        self.spr_dat_cfgr <<= or1200cfgr.spr_dat_o

        # Instantiation of CPU's SPRS block %%5
        or1200sprs = Or1200sprs_wire()
        or1200sprs.rst <<= self.rst
        or1200sprs.addrbase <<= self.operand_a
        or1200sprs.addrofs <<= self.spr_addrimm
        or1200sprs.dat_i <<= self.operand_b
        or1200sprs.alu_op <<= self.alu_op
        or1200sprs.flagforw <<= self.flagforw
        or1200sprs.flag_we <<= self.flag_we
        self.flag <<= or1200sprs.flag
        or1200sprs.cyforw <<= self.cyforw
        or1200sprs.cy_we <<= self.cy_we
        self.carry <<= or1200sprs.carry
        self.sprs_dataout <<= or1200sprs.to_wbmux_out
        or1200sprs.du_addr <<= self.du_addr
        or1200sprs.du_dat_du <<= self.du_dat_du
        or1200sprs.du_read <<= self.du_read
        or1200sprs.du_write <<= self.du_write
        self.du_dat_cpu <<= or1200sprs.du_dat_cpu
        self.spr_addr <<= or1200sprs.spr_addr_out
        or1200sprs.spr_dat_pic <<= self.spr_dat_pic
        or1200sprs.spr_dat_tt <<= self.spr_dat_tt
        or1200sprs.spr_dat_pm <<= self.spr_dat_pm
        or1200sprs.spr_dat_cfgr <<= self.spr_dat_cfgr
        or1200sprs.spr_dat_rf <<= self.spr_dat_rf
        or1200sprs.spr_dat_npc <<= self.spr_dat_npc
        or1200sprs.spr_dat_ppc <<= self.spr_dat_ppc
        or1200sprs.spr_dat_du <<= self.spr_dat_du
        self.spr_dat_cpu <<= or1200sprs.spr_dat_o_out
        self.spr_cs <<= or1200sprs.spr_cs_out
        self.spr_we <<= or1200sprs.spr_we
        self.epcr_we <<= or1200sprs.epcr_we
        self.eear_we <<= or1200sprs.eear_we
        self.esr_we <<= or1200sprs.esr_we
        self.pc_we <<= or1200sprs.pc_we
        or1200sprs.epcr <<= self.epcr
        or1200sprs.eear <<= self.eear
        or1200sprs.esr <<= self.esr
        or1200sprs.except_started <<= self.except_started
        self.sr_we <<= or1200sprs.sr_we_out
        self.to_sr <<= or1200sprs.to_sr_out
        self.sr <<= or1200sprs.sr_out
        or1200sprs.branch_op <<= self.branch_op


        # self.write_spr = pyrtl.WireVector(bitwidth=1)  # , name='write_spr')  # Write SPR
        # # self.test_write_spr = pyrtl.Output(bitwidth=1,name='test_write_spr')  # , name='write_spr')  # Write SPR
        # # self.test_write_spr<<=self.write_spr
        # self.read_spr = pyrtl.WireVector(bitwidth=1)  # , name='read+spr') # Read SPR
        # self.cfgr_sel = pyrtl.WireVector(bitwidth=1)  # , name='cfgr_sel') # Select for cfg regs
        # self.rf_sel = pyrtl.WireVector(bitwidth=1)  # , name='rf_sel') # Select for for RF
        # self.npc_sel = pyrtl.WireVector(bitwidth=1)  # , name='npc_sel') # Select for for NPC
        # self.ppc_sel = pyrtl.WireVector(bitwidth=1)  # , name='ppc_sel') # Select for for PPC
        # self.sr_sel = pyrtl.WireVector(bitwidth=1)  # , name='sr_sel') # Select for for SR
        # self.epcr_sel = pyrtl.WireVector(bitwidth=1)  # , name='epcr_sel') # Select for for EPCR0
        # self.eear_sel = pyrtl.WireVector(bitwidth=1)  # , name='eear_sel') # Select for for EEAR0
        # self.esr_sel = pyrtl.WireVector(bitwidth=1)  # , name='esr_sel') # Select for for ESR0
        # self.sys_data = pyrtl.WireVector(bitwidth=32)  # , name='sys_data') # Read data from system SPRs
        # self.du_access = pyrtl.WireVector(bitwidth=1)  # , name='du_access') # Debug unit access
        # self.sprs_op = pyrtl.WireVector(
        #     bitwidth=or1200_definitions.OR1200_ALUOP_WIDTH)  # , name='sprs_op') # ALU operation
        # self.unqualified_cs = pyrtl.WireVector(bitwidth=32)  # , name='unqualified_cs') # Unqualified chip selects
        # self.to_wbmux = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_OPERAND_WIDTH)  # , name='to_wbmux') # For l.mfspr
        #
        # # Decide if it is debug unit access
        #
        # self.sprs_dataout <<= self.to_wbmux
        # # Decide if it is debug unit access
        # self.du_access <<= self.du_read | self.du_write
        #
        # # Generate sprs opcode
        # self.sprs_op <<= pyrtl.select(self.du_write, or1200_definitions.OR1200_ALUOP_MTSR,
        #                               pyrtl.select(self.du_read, or1200_definitions.OR1200_ALUOP_MFSR, self.alu_op))
        #
        # # Generate SPR address from base address and offset
        # # OR from debug unit address
        # self.spr_addr <<= pyrtl.select(self.du_access, self.du_addr, (self.operand_a | self.spr_addrimm.zero_extended(32)))
        #
        # # SPR is written by debug unit or by l.mtspr
        # self.spr_dat_cpu <<= pyrtl.select(self.du_write, self.du_dat_du, self.operand_b)
        #
        # # debug unit data input:
        # #  - write into debug unit SPRs by debug unit itself
        # #  - read of SPRS by debug unit
        # #  - write into debug unit SPRs by l.mtspr
        # self.du_dat_cpu <<= pyrtl.select(self.du_write, self.du_dat_du,
        #                                  pyrtl.select(self.du_read, self.to_wbmux, self.operand_b))
        #
        # # Write into SPRs when l.mtspr
        # self.spr_we <<= self.du_write | self.write_spr
        #
        # # Qualify chip selects
        # self.spr_cs <<= self.unqualified_cs & pyrtl.concat_list(32 * [self.read_spr | self.write_spr])
        #
        # to_sr = [i for i in self.to_sr]
        # # What to write into SR
        # sr_f = self.branch_op == or1200_definitions.OR1200_BRANCHOP_RFE
        #
        # # self.test_sr_f=pyrtl.Output(bitwidth=1,name='test_sr_f')
        # # self.test_sr_f <<= sr_f
        # sr_rtl_all = pyrtl.rtl_all(self.write_spr, self.sr_sel)
        # # self.test_sr_f = pyrtl.Output(bitwidth=1, name='test_sr_rtl_all')
        # # self.test_sr_f <<= sr_rtl_all
        # sr_OV_concat = pyrtl.concat(or1200_definitions.ONE,self.spr_dat_cpu[or1200_definitions.OR1200_SR_OV: or1200_definitions.OR1200_SR_FO])
        # # self.test_sr_OV_concat = pyrtl.Output(bitwidth=or1200_definitions.OR1200_SR_FO + 1-or1200_definitions.OR1200_SR_OV,name='test_sr_OV_concat')
        # # self.test_sr_OV_concat<<=sr_OV_concat
        # sr_OV_mux = mux(sr_rtl_all, sr_OV_concat,self.sr[or1200_definitions.OR1200_SR_OV: or1200_definitions.OR1200_SR_FO + 1])
        # # self.test_sr_OV_mux = pyrtl.Output(
        # #     bitwidth=or1200_definitions.OR1200_SR_FO + 1 - or1200_definitions.OR1200_SR_OV, name='test_sr_OV')
        # # self.test_sr_OV_mux <<= sr_OV_mux
        # sr_OV =  mux(sr_f,
        #     self.esr[or1200_definitions.OR1200_SR_OV: or1200_definitions.OR1200_SR_FO + 1],
        #     sr_OV_mux)
        # # self.test_esr = pyrtl.Output(
        # #     bitwidth=or1200_definitions.OR1200_SR_FO + 1 - or1200_definitions.OR1200_SR_OV, name='test_esr')
        # # self.test_esr<<=self.esr[or1200_definitions.OR1200_SR_OV: or1200_definitions.OR1200_SR_FO + 1]
        #
        # OV = [i for i in sr_OV]
        #
        #
        # for i in range(or1200_definitions.OR1200_SR_OV, or1200_definitions.OR1200_SR_FO + 1):
        #    to_sr[i] = OV[i-or1200_definitions.OR1200_SR_OV]
        #
        # sr_CY_mux_mux = mux(sr_rtl_all,self.spr_dat_cpu[or1200_definitions.OR1200_SR_CY],self.sr[or1200_definitions.OR1200_SR_CY])
        # sr_CY_mux = mux(self.cy_we, self.cyforw, sr_CY_mux_mux)
        # sr_CY = mux(sr_f,
        #     self.esr[or1200_definitions.OR1200_SR_CY: or1200_definitions.OR1200_SR_CY + 1],
        #     sr_CY_mux)
        # CY = [i for i in sr_CY]
        #
        # for i  in range(or1200_definitions.OR1200_SR_CY, or1200_definitions.OR1200_SR_CY + 1):
        #     to_sr[i] = CY[i-or1200_definitions.OR1200_SR_CY]
        #
        # sr_F_mux_mux = mux(sr_rtl_all,self.spr_dat_cpu[or1200_definitions.OR1200_SR_F],self.sr[or1200_definitions.OR1200_SR_F])
        # sr_F_mux = mux(self.flag_we, self.flagforw,sr_F_mux_mux)
        # sr_F = mux(sr_f, self.esr[or1200_definitions.OR1200_SR_F],sr_F_mux)
        # F = [i for i in sr_F]
        #
        # for i in range(or1200_definitions.OR1200_SR_F, or1200_definitions.OR1200_SR_F + 1):
        #     to_sr[i] = F[i-or1200_definitions.OR1200_SR_F]
        #
        #
        # sr_SM_mux = mux(sr_rtl_all,self.spr_dat_cpu[or1200_definitions.OR1200_SR_SM: or1200_definitions.OR1200_SR_CE + 1],
        #                  self.sr[or1200_definitions.OR1200_SR_SM: or1200_definitions.OR1200_SR_CE + 1])
        # sr_SM = mux(sr_f,
        #     self.esr[or1200_definitions.OR1200_SR_SM: or1200_definitions.OR1200_SR_CE + 1],
        #     sr_SM_mux)
        # SM = [i for i in sr_SM]
        #
        # for i in range(or1200_definitions.OR1200_SR_SM, or1200_definitions.OR1200_SR_CE + 1):
        #     to_sr[i] = SM[i-or1200_definitions.OR1200_SR_SM]
        #
        # self.to_sr.next <<= pyrtl.concat(*reversed(to_sr))
        #
        # # Selects for system SPRs
        # self.cfgr_sel <<= pyrtl.rtl_all(self.spr_cs[or1200_definitions.OR1200_SPR_GROUP_SYS.val],
        #                                 (self.spr_addr[4:11] == or1200_definitions.OR1200_SPR_CFGR))
        # self.rf_sel <<= pyrtl.rtl_all(self.spr_cs[or1200_definitions.OR1200_SPR_GROUP_SYS.val],
        #                               (self.spr_addr[5:11] == or1200_definitions.OR1200_SPR_RF))
        # self.npc_sel <<= pyrtl.rtl_all(self.spr_cs[or1200_definitions.OR1200_SPR_GROUP_SYS.val],
        #                                (self.spr_addr[0:11] == or1200_definitions.OR1200_SPR_NPC))
        # self.ppc_sel <<= pyrtl.rtl_all(self.spr_cs[or1200_definitions.OR1200_SPR_GROUP_SYS.val],
        #                                (self.spr_addr[0:11] == or1200_definitions.OR1200_SPR_PPC))
        # self.sr_sel <<= pyrtl.rtl_all(self.spr_cs[or1200_definitions.OR1200_SPR_GROUP_SYS.val],
        #                               (self.spr_addr[0:11] == or1200_definitions.OR1200_SPR_SR))
        # self.epcr_sel <<= pyrtl.rtl_all(self.spr_cs[or1200_definitions.OR1200_SPR_GROUP_SYS.val],
        #                                 (self.spr_addr[0:11] == or1200_definitions.OR1200_SPR_EPCR))
        # self.eear_sel <<= pyrtl.rtl_all(self.spr_cs[or1200_definitions.OR1200_SPR_GROUP_SYS.val],
        #                                 (self.spr_addr[0:11] == or1200_definitions.OR1200_SPR_EEAR))
        # self.esr_sel <<= pyrtl.rtl_all(self.spr_cs[or1200_definitions.OR1200_SPR_GROUP_SYS.val],
        #                                (self.spr_addr[0:11] == or1200_definitions.OR1200_SPR_ESR))
        #
        # # Write enables for system SPRs
        # self.sr_we <<= pyrtl.rtl_all(self.write_spr, self.sr_sel) | (
        #             self.branch_op == or1200_definitions.OR1200_BRANCHOP_RFE) | self.flag_we | self.cy_we
        # self.pc_we <<= pyrtl.rtl_all(self.write_spr, (self.npc_sel | self.ppc_sel))
        # self.epcr_we <<= pyrtl.rtl_all(self.write_spr, self.epcr_sel)
        # self.eear_we <<= pyrtl.rtl_all(self.write_spr, self.eear_sel)
        # self.esr_we <<= pyrtl.rtl_all(self.write_spr, self.esr_sel)
        #
        # # Output from system SPRs
        # self.sys_data <<= (self.spr_dat_cfgr & pyrtl.concat_list(32 * [self.read_spr & self.cfgr_sel])) | \
        #                   (self.spr_dat_rf & pyrtl.concat_list(32 * [self.read_spr & self.rf_sel])) | \
        #                   (self.spr_dat_npc & pyrtl.concat_list(32 * [self.read_spr & self.npc_sel])) | \
        #                   (self.spr_dat_ppc & pyrtl.concat_list(32 * [self.read_spr & self.ppc_sel])) | \
        #                   (pyrtl.concat((pyrtl.Const(32) - pyrtl.concat_list(
        #                       or1200_definitions.OR1200_SR_WIDTH * [or1200_definitions.ZERO])), self.sr) \
        #                    & (pyrtl.concat_list(32 * [self.read_spr & self.sr_sel]))) | \
        #                   (self.epcr & (pyrtl.concat_list(32 * [self.read_spr & self.epcr_sel]))) | \
        #                   (self.eear & pyrtl.concat_list(32 * [self.read_spr & self.eear_sel])) | \
        #                   (pyrtl.concat((pyrtl.Const(32) - pyrtl.concat_list(
        #                       or1200_definitions.OR1200_SR_WIDTH * [or1200_definitions.ZERO])), self.esr) \
        #                    & (pyrtl.concat_list(32 * [self.read_spr & self.esr_sel])))
        #
        # # Flag alias
        # self.flag <<= self.sr[or1200_definitions.OR1200_SR_F]
        #
        # # Carry alias
        # self.carry <<= self.sr[or1200_definitions.OR1200_SR_CY]
        #
        # # initialize all the parts
        # superReg = SuperReg()
        # minterface = Minterface()
        # decodingGroups = DecodingGroups()
        #
        # superReg.rst <<= self.rst
        # superReg.sr_we <<= self.sr_we
        # superReg.except_started <<= self.except_started
        # superReg.to_sr <<= self.to_sr
        # self.sr <<= superReg.sr
        # minterface.sprs_op <<= self.sprs_op
        # minterface.spr_addr <<= self.spr_addr
        # minterface.sys_data <<= self.sys_data
        # minterface.spr_dat_pic <<= self.spr_dat_pic
        # minterface.spr_dat_pm <<= self.spr_dat_pm
        # minterface.spr_dat_du <<= self.spr_dat_du
        # minterface.spr_dat_tt <<= self.spr_dat_tt
        # self.to_wbmux <<= minterface.to_wbmux
        # self.write_spr <<= minterface.write_spr
        # self.read_spr <<= minterface.read_spr
        # decodingGroups.spr_addr <<= self.spr_addr
        # self.unqualified_cs <<= decodingGroups.unqualified_cs


class DecodingGroups(object):
    def __init__(self):
        self.spr_addr = pyrtl.WireVector(bitwidth=32)  # SPR Address

        self.unqualified_cs = pyrtl.WireVector(bitwidth=32)  # Unqualified chip selects

        with pyrtl.conditional_assignment:
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(0,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000000000000001, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(1,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000000000000010, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(2,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000000000000100, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(3,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000000000001000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(4,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000000000010000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(5,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000000000100000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(6,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000000001000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(7,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000000010000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(8,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000000100000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(9,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000001000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(10,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000010000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(11,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000000100000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(12,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000001000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(13,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000010000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(14,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000000100000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(15,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000001000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(16,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000010000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(17,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000000100000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(18,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000001000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(19,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000010000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(20,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000000100000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(21,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000001000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(22,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000010000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(23,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000000100000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(24,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000001000000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(25,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000010000000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(26,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00000100000000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(27,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00001000000000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(28,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00010000000000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(29,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b00100000000000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(30,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b01000000000000000000000000000000, bitwidth=32)
            with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == pyrtl.Const(31,
                                                                                        bitwidth=or1200_definitions.OR1200_SPR_GROUP_WIDTH):
                self.unqualified_cs |= pyrtl.Const(0b10000000000000000000000000000000, bitwidth=32)


# Supervision register
class SuperReg(object):
    def __init__(self):
        self.rst = pyrtl.WireVector(bitwidth=1)  # Reset
        self.sr_we = pyrtl.WireVector(bitwidth=1)  # Write enable SR
        self.except_started = pyrtl.WireVector(bitwidth=1)  # Exception was started
        self.to_sr = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_SR_WIDTH)  # Data to SR
        self.sr = pyrtl.Register(bitwidth=or1200_definitions.OR1200_SR_WIDTH)  # SR

        sr = [i for i in self.sr]
        with pyrtl.conditional_assignment:
            with self.rst:
                self.sr.next |= pyrtl.concat(pyrtl.Const(0b1, bitwidth=1), or1200_definitions.OR1200_SR_EPH_DEF, \
                                             pyrtl.concat_list((or1200_definitions.OR1200_SR_WIDTH - 3) * [
                                                 pyrtl.Const(0b0, bitwidth=1)]), \
                                             pyrtl.Const(0b1, bitwidth=1))  # #1
            with self.except_started:
                sr[or1200_definitions.OR1200_SR_SM] = pyrtl.Const(0b1)
                sr[or1200_definitions.OR1200_SR_TEE] = pyrtl.Const(0b0)
                sr[or1200_definitions.OR1200_SR_IEE] = pyrtl.Const(0b0)
                sr[or1200_definitions.OR1200_SR_DME] = pyrtl.Const(0b0)
                sr[or1200_definitions.OR1200_SR_IME] = pyrtl.Const(0b0)
                self.sr.next |= pyrtl.concat(*reversed(sr))
                # self.sr = pyrtl.bitfield_update(self.sr, or1200_definitions.OR1200_SR_SM, or1200_definitions.OR1200_SR_SM+1, pyrtl.Const(0b1, bitwidth=1))
                # self.sr = pyrtl.bitfield_update(self.sr, or1200_definitions.OR1200_SR_TEE, or1200_definitions.OR1200_SR_TEE+1, pyrtl.Const(0b0, bitwidth=1))
                # self.sr = pyrtl.bitfield_update(self.sr, or1200_definitions.OR1200_SR_IEE, or1200_definitions.OR1200_SR_IEE+1, pyrtl.Const(0b0, bitwidth=1))
                # self.sr = pyrtl.bitfield_update(self.sr, or1200_definitions.OR1200_SR_DME, or1200_definitions.OR1200_SR_DME+1, pyrtl.Const(0b0, bitwidth=1))
                # self.sr = pyrtl.bitfield_update(self.sr, or1200_definitions.OR1200_SR_IME, or1200_definitions.OR1200_SR_IME+1, pyrtl.Const(0b0, bitwidth=1))
            with self.sr_we:
                self.sr.next |= self.to_sr[0:or1200_definitions.OR1200_SR_WIDTH]  # #1


# MTSPR/MFSPR interface
class Minterface(object):
    def __init__(self):
        self.sprs_op = pyrtl.WireVector(bitwidth=or1200_definitions.OR1200_ALUOP_WIDTH)  # ALU operation
        self.spr_addr = pyrtl.WireVector(bitwidth=32)  # SPR Address
        self.sys_data = pyrtl.WireVector(bitwidth=32)  # Read data from system SPRs
        self.spr_dat_pic = pyrtl.WireVector(bitwidth=32)  # Data from PIC
        self.spr_dat_pm = pyrtl.WireVector(bitwidth=32)  # Data from PM
        self.spr_dat_du = pyrtl.WireVector(bitwidth=32)  # Data from DU
        self.spr_dat_tt = pyrtl.WireVector(bitwidth=32)  # Data from TT

        self.to_wbmux = pyrtl.WireVector(bitwidth=dw)  # For l.mfspr
        self.write_spr = pyrtl.WireVector(bitwidth=1)  # Write SPR
        self.read_spr = pyrtl.WireVector(bitwidth=1)  # Read SPR

        with pyrtl.conditional_assignment:
            with self.sprs_op == or1200_definitions.OR1200_ALUOP_MTSR:
                self.to_wbmux |= pyrtl.Const(0b0, bitwidth=32)
                self.write_spr |= pyrtl.Const(0b1, bitwidth=1)
                self.read_spr |= pyrtl.Const(0b0, bitwidth=1)
            with self.sprs_op == or1200_definitions.OR1200_ALUOP_MFSR:
                with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == or1200_definitions.OR1200_SPR_GROUP_TT:
                    self.to_wbmux |= self.spr_dat_tt
                with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == or1200_definitions.OR1200_SPR_GROUP_PIC:
                    self.to_wbmux |= self.spr_dat_pic
                with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == or1200_definitions.OR1200_SPR_GROUP_PM:
                    self.to_wbmux |= self.spr_dat_pm
                with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == or1200_definitions.OR1200_SPR_GROUP_DU:
                    self.to_wbmux |= self.spr_dat_du
                with self.spr_addr[or1200_definitions.OR1200_SPR_GROUP_BITS] == or1200_definitions.OR1200_SPR_GROUP_SYS:
                    self.to_wbmux |= self.sys_data
                with pyrtl.otherwise:
                    self.to_wbmux |= pyrtl.Const(0b0, bitwidth=32)
                self.write_spr |= pyrtl.Const(0b0, bitwidth=1)
                self.read_spr |= pyrtl.Const(0b1, bitwidth=1)
            with pyrtl.otherwise:
                self.write_spr |= pyrtl.Const(0b0, bitwidth=1)
                self.read_spr |= pyrtl.Const(0b0, bitwidth=1)
                self.to_wbmux |= pyrtl.Const(0b0, bitwidth=32)


if __name__ == '__main__':
    cpu = Or1200Cpu()

    #sim = pyrtl.GPUSim_now1line.GPUSim('cpu')
    # com = pyrtl.CompiledSimulation()

    input_width = []
    from pyrtl.wire import Input

    IN = pyrtl.working_block().wirevector_subset(Input)
    for inn in IN:
        name = inn.name
        width = inn.bitwidth
        input_width.append([name, width])
    import random

    max_ = 0
    com_time = 0
    ess_time = 0
    num = 1
    for i in range(num):
        print(i)

        inputs_random = {}
        inputs_select = {}
        inputs_old = {}
        inputs_ = {}

        for inp in input_width:
            inputs_random[inp[0]] = []
            inputs_select[inp[0]] = []
            result = random.randint(0, 2 ** inp[1] - 1)
            inputs_old[inp[0]] = result

        for j in range(131072):
            for inp in input_width:
                result = random.randint(0, 2 ** inp[1] - 1)
                inputs_[inp[0]] = result
                inputs_random[inp[0]].append(result)
            if random.random() < 0.2:
                for name in inputs_old:
                    inputs_select[name].append(inputs_old[name])
            else:
                for name in inputs_:
                    inputs_select[name].append(inputs_[name])
                    inputs_old[name] = inputs_[name]
        #time1 = com.step_multiple(inputs_select)
    sim = pyrtl.GPUSim_now_loopcpugpu_dll.GPUSim('cpu_reg', 64, 10)
    #sim = pyrtl.GPUSim_now_nonloop.GPUSim('cpu', 64,10)
    sim.make_input(inputs_select)